package longshu.srpc.server.impl;

import lombok.extern.slf4j.Slf4j;
import longshu.srpc.IOUtils;
import longshu.srpc.api.RpcService;
import longshu.srpc.server.RpcAcceptor;
import longshu.srpc.server.RpcServer;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * SimpleRpcServer
 *
 * @author LongShu 2017/12/03
 */
@Slf4j
public class SimpleRpcServer implements RpcServer {

    private RpcAcceptor rpcAcceptor;
    private volatile boolean running = false;

    private ConcurrentMap<String, RpcService> serviceHander = new ConcurrentHashMap<>();

    public SimpleRpcServer(SimpleRpcAcceptor rpcAcceptor) {
        this.rpcAcceptor = rpcAcceptor;

        SimpleRpcProcessor rpcProcessor = new SimpleRpcProcessor();
        rpcAcceptor.setRpcProcessor(rpcProcessor);
        rpcProcessor.setRpcServer(this);
    }

    @Override
    public void start() {
        log.info("start...");
        if (!isRunning()) {
            rpcAcceptor.accept();
            running = true;
        } else {
            log.info("is already start!");
        }
    }

    public void stop() {
        log.info("stop...");
        if (isRunning()) {
            IOUtils.close(rpcAcceptor);
        } else {
            log.info("is already stop!");
        }
    }

    @Override
    public boolean isRunning() {
        return running;
    }

    @Override
    public void export(Class<? extends RpcService> serviceInterface, Class<? extends RpcService> serviceImpl) {
        log.debug("serviceInterface: {} \nserviceImpl: {}", serviceInterface, serviceImpl);
        checkService(serviceInterface, serviceImpl);

        String serviceName = serviceInterface.getName();
        if (serviceHander.containsKey(serviceName)) {
            log.info("serviceName： {} exist!", serviceName);
        }
        try {
            RpcService servieInstance = serviceImpl.newInstance();
            serviceHander.put(serviceName, servieInstance);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void export(Class<? extends RpcService> serviceInterface, RpcService servieInstance) {
        log.debug("serviceInterface: {} \nservieInstance: {}", serviceInterface, servieInstance);
        checkService(serviceInterface, servieInstance);

        String serviceName = serviceInterface.getName();
        if (serviceHander.containsKey(serviceName)) {
            log.info("serviceName： {} exist!", serviceName);
        }
        serviceHander.put(serviceName, servieInstance);
    }

    RpcService getRpcService(Class<? extends RpcService> serviceInterface) {
        RpcService rpcService = serviceHander.get(serviceInterface.getName());

        return rpcService;
    }

    RpcService getRpcService(String serviceName) {
        RpcService rpcService = serviceHander.get(serviceName);

        return rpcService;
    }

    private void checkService(Class<? extends RpcService> serviceInterface, Class<? extends RpcService> serviceImpl) {
        if (serviceInterface == null || serviceImpl == null) {
            throw new IllegalArgumentException("serviceInterface and serviceImpl can not null !");
        }
        if (serviceImpl.isInterface()) {
            throw new IllegalArgumentException("Invalid  serviceImpl:" + serviceImpl);
        }
        if (!serviceInterface.isAssignableFrom(serviceImpl)) {
            throw new IllegalArgumentException("serviceImpl must impl serviceInterface!");
        }
    }

    private void checkService(Class<? extends RpcService> serviceInterface, RpcService servieInstance) {
        if (serviceInterface == null || servieInstance == null) {
            throw new IllegalArgumentException("serviceInterface and servieInstance can not null !");
        }
        if (!serviceInterface.isInstance(servieInstance)) {
            throw new IllegalArgumentException("servieInstance must impl serviceInterface !");
        }
    }

}
